/*
   Copyright (c) [Year] [name of copyright holder]
   [Software Name] is licensed under Mulan PSL v2.
   You can use this software according to the terms and conditions of the Mulan PSL v2. 
   You may obtain a copy of Mulan PSL v2 at:
            http://license.coscl.org.cn/MulanPSL2 
   THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.  
   See the Mulan PSL v2 for more details.  
*/

#ifndef JIAJIA_JJENV_HPP
#define JIAJIA_JJENV_HPP

#include"jiajiastd.hpp"
#include"jjtoken.hpp"
#include"jjsymtab.hpp"
#include"jjir.hpp"

namespace jiajia{
    // jiajia 一些环境的解释

    // IF STMT
    // IF, 类型 irnode * , 表示判断的语句, [IFXXX, ...]
    // IF_GOTO, 类型 irnode * , 表示绕过 else 或者其他语句的语句, [GOTO, ...]
    // IF_ELSE, 类型 irnode * , 表示否则语句的开头

    // LOOP STMT
    // LOOP_FINIT, 类型 irnode * , 表示初始化 factor 的语句, [ASSIGN, ..., factor]
    // LOOP_FMOVE, 类型 irnode * , 表示 factor 前进的语句, [ADD, ... ]
    // 存储不同环境的一些值
    struct jjenvnode{
        enum modeEnum{
            MODE_BEGIN = 0,
            EMPTY_MODE = MODE_BEGIN,
            INIT_MODE,
            SEQ_MODE,
            IF_MODE,
            ELSE_MODE,
            ELIF_MODE,
            LOOP_MODE,
            UNITIL_MODE,
            CALL_MODE,
            ASSIGN_MODE,
            MODE_END
        };

        enum attrEnum{
            ATTR_BEGIN = 0,
            BEGIN = ATTR_BEGIN,
            END,
            ATTR_MID,
            // 初始环境
            INIT_END = ATTR_MID,
            // 数组初始环境
            SEQ_MAIN = ATTR_MID,
            SEQ_TA,
            SEQ_PUSH,
            SEQ_GID,
            SEQ_END,
            // if_stmt
            IF_COND = ATTR_MID,
            IF_GOTO,
            ELIF_COND,
            ELIF_GOTO,
            IF_END,
            // loop_stmt
            LOOP_FACTOR = ATTR_MID,
            LOOP_FINIT,
            LOOP_FMOVE,
            LOOP_GOTO,
            LOOP_BREAK,
            LOOP_END,
            // call
            CALL_FUNC = ATTR_MID,
            CALL_RESULT,
            CALL_END,
            // assign
            ASSIGN_RESULT = ATTR_MID,
            ASSIGN_END,
        };

        union valueType{
            value_t * value;
            jjirnode * node;
            func_t func;
        };

        static const size_t attr_size = my::intMax<INIT_END, SEQ_END, IF_END, LOOP_END, CALL_END, ASSIGN_END>::value;

        enum_t mode;
        valueType attr[attr_size];

        jjenvnode():mode(EMPTY_MODE), attr(){}
        jjenvnode(const jjenvnode & e):mode(e.mode){
            for(size_t i = 0; i < attr_size; ++i)
                attr[i] = e.attr[i];
        }

        jjenvnode & operator=(jjenvnode & e){
            if(this == &e) return *this;
            mode = e.mode;
            for(size_t i = 0; i < attr_size; ++i)
                attr[i] = e.attr[i];
        }

        ~jjenvnode(){}

        // 进入 init 初始环境
        void enterINIT(jjirnode * begin, jjirnode * end){
            mode = INIT_MODE;
            attr[BEGIN].node = begin;
            attr[END].node = end;
        }

        // 进入 if 环境
        void enterIF(jjirnode * begin, jjirnode * end, jjirnode * cond_ir){
            mode = IF_MODE;
            attr[BEGIN].node = begin;
            attr[END].node = end;
            attr[IF_COND].node = cond_ir;
            attr[IF_GOTO].node = nullptr;
            attr[ELIF_COND].node = nullptr;
            attr[ELIF_GOTO].node = nullptr;
        }

        void enterELSE(jjirnode * goto_ir, jjirnode * else_ir){
            if(mode == IF_MODE){
                mode = ELSE_MODE;
                attr[IF_COND].node->backfillGoto(else_ir);
                attr[IF_GOTO].node = goto_ir;
            }else if(mode == ELIF_MODE){
                mode = ELIF_MODE;
                attr[ELIF_COND].node->backfillGoto(else_ir);
                attr[ELIF_GOTO].node = goto_ir;
            }
        }

        void enterELIF(jjirnode * goto_ir, jjirnode * cond_ir, jjirnode * false_ir){
            if(mode == IF_MODE){
                mode = ELIF_MODE;
                // 如果为 IF_MODE ，则替换 IF_COND 的跳转，设置 IF_GOTO 的节点
                attr[IF_COND].node->backfillGoto(false_ir);
                attr[IF_GOTO].node = goto_ir;
                attr[ELIF_COND].node = cond_ir;
                attr[ELIF_GOTO].node = nullptr;
            }else if(mode == ELIF_MODE){
                // 如果为 ELIF_MODE ，则替换 ELIF_COND 的跳转，设置 ELIF_GOTO 的节点
                attr[ELIF_COND].node->backfillGoto(false_ir);
                attr[ELIF_COND].node = cond_ir;
                attr[ELIF_GOTO].node = goto_ir;
            }
        }

        // 进入 loop 环境
        void enterLOOP(jjirnode * begin, jjirnode * end, value_t * factor, jjirnode * finit_ir, jjirnode * fmove_ir, jjirnode * goto_ir, jjirnode * break_ir){
            mode = LOOP_MODE;
            attr[BEGIN].node = begin;
            attr[END].node = end;
            attr[LOOP_FACTOR].value = factor;
            attr[LOOP_FINIT].node = finit_ir;
            attr[LOOP_FMOVE].node = fmove_ir;
            attr[LOOP_GOTO].node = goto_ir;
            attr[LOOP_BREAK].node = break_ir;
        }

        void enterUNTIL(jjirnode * cond){
            attr[LOOP_GOTO].node = cond;
            mode = UNITIL_MODE;
        }

        // 进入函数调用环境
        void enterCALL(jjirnode * begin, jjirnode * end, func_t f, value_t * result){
            mode = CALL_MODE;
            attr[BEGIN].node = begin;
            attr[END].node = end;
            attr[CALL_FUNC].func = f;
            attr[CALL_RESULT].value = result;
        }

        // 进入 assign 环境
        void enterASSIGN(jjirnode * begin, jjirnode * end, value_t * result){
            mode = ASSIGN_MODE;
            attr[BEGIN].node = begin;
            attr[END].node = end;
            attr[ASSIGN_RESULT].value = result;
        }

        // 进入 SEQ 环境
        void enterSEQ(jjirnode * begin, jjirnode * end, value_t * main_val, value_t * ta_val){
            mode = SEQ_MODE;
            attr[BEGIN].node = begin;
            attr[END].node = end;
            attr[SEQ_MAIN].value = main_val;    // 当前主值数组
            attr[SEQ_TA].value = ta_val;        // 当前主值节点，其主值为 SEQ_MAIN
            attr[SEQ_GID].node = nullptr;
            attr[SEQ_PUSH].node = begin;
        }

        void enterPUSH(jjirnode * node){
            if(mode != SEQ_MODE) return;
            attr[SEQ_GID].node = nullptr;
            attr[SEQ_PUSH].node = node;
        }

        inline jjirnode * begin(){
            return attr[BEGIN].node;
        }

        inline jjirnode * end(){
            return attr[END].node;
        }

        inline value_t * value(enum_t e){
            return attr[e].value;
        }

        inline jjirnode * node(enum_t e){
            return attr[e].node;
        }

        inline func_t func(enum_t e){
            return attr[e].func;
        }

        inline void setValue(enum_t e, value_t * val){
            attr[e].value = val;
        }

        inline void setNode(enum_t e, jjirnode * node){
            attr[e].node = node;
        }

        inline void setFunc(enum_t e, func_t f){
            attr[e].func = f;
        }
    };

    // jjenv 环境类，保存 jiajia 现在所处的阶段和一些关键值
    class jjenv{
    private:
        std::deque<jjenvnode> mStack;
        bool mLHSFlag;
        value_t * mMainValue;

    public:
        jjenv():
            mStack(),
            mLHSFlag(true),
            mMainValue(nullptr)
        {
            jjenvnode e;
            e.enterINIT(nullptr, nullptr);
            mStack.push_back(std::move(e));
        }

        inline bool lhsFlag(){ return mLHSFlag; }
        inline void toRHS(){ mLHSFlag = false; }
        inline void toLHS(){ mLHSFlag = true; }

        inline value_t * mainValue(){
            return mMainValue;
        }

        inline void setMainValue(value_t * val){
            mMainValue = val;
        }

        // 返回当前 LOOP_MODE 的循环因子
        value_t * loopFactor(){
            jjenvnode & e = mStack.back();
            if(e.mode == jjenvnode::LOOP_MODE || e.mode == jjenvnode::UNITIL_MODE)
                return e.attr[jjenvnode::LOOP_FACTOR].value;
            return nullptr;
        }

        // if
        bool enterIF(const jjtoken & t, jjir & ir, value_t * val){
            // 如果xxx，xxx，结束
            // begin    :   [code::IFFALSE, val, end]
            // body         ...
            // end      :   ...
            jjenvnode e;
            jjirnode * begin = nullptr;
            jjirnode * end = ir.insertBack(topEnd());
            jjirnode * cond = ir.insertBack(end);

            begin = cond;
            end->genGOTONEXT();
            cond->genIF(code::IFFALSE, val, end);
            cond->setToken(t);

            e.enterIF(begin, end, cond);
            mStack.push_back(e);
            return true;
        }

        // elif
        bool enterELIF(const jjtoken & t, jjir & ir, jjirnode * expr_begin, value_t * val){
            // 如果xxx，xxx，但如果，xxx，结束

            // 如果xxx，xxx，但如果xxx，否则，xxx，结束
            // begin, IF_COND   :   [code::IFFALSE, val1, ELIF_COND]
            // body             :   ...
            // goto, IF_GOTO    :   [code::GOTO, end]
            // cond, ELIF_COND  :   [code::IFFALSE, val2, else_ir]
            // ELIF_GOTO        :   [code::GOTO, end]
            // else_ir          :   ...
            // end              :   ...

            jjenvnode & e = mStack.back();
            if(e.mode != jjenvnode::IF_MODE && e.mode != jjenvnode::ELIF_MODE) return false;

            // 该 goto_ir 语句是上一个 if 或 elif 语句的 goto 语句
            jjirnode * goto_ir = ir.insertBack((expr_begin != nullptr)? expr_begin:e.end());
            goto_ir->genGOTO(e.end());

            jjirnode * cond_ir = ir.insertBack(e.end());
            cond_ir->genIF(code::IFFALSE, val, e.end());
            cond_ir->setToken(t);

            e.enterELIF(goto_ir, cond_ir, (expr_begin != nullptr)? expr_begin:cond_ir);
            return true;
        }

        // else
        bool enterELSE(jjir & ir){
            // 如果xxx，xxx，否则，xxx，结束
            // begin, IF_COND   :   [code::IFFALSE, val, else_ir]
            // body             :   ...
            // goto, IF_GOTO    :   [code::GOTO, end]
            // else_ir          :   ...
            // end              :   ...

            // 如果xxx，xxx，但如果xxx，否则，xxx，结束
            // begin, IF_COND   :   [code::IFFALSE, val1, ELIF_COND]
            // body             :   ...
            // IF_GOTO          :   [code::GOTO, end]
            // ELIF_COND        :   [code::IFFALSE, val2, else_ir]
            // goto, ELIF_GOTO  :   [code::GOTO, end]
            // else_ir          :   ...
            // end              :   ...

            jjenvnode & e = mStack.back();
            if(e.mode != jjenvnode::IF_MODE && e.mode != jjenvnode::ELIF_MODE) return false;

            jjirnode * goto_ir = ir.insertBack(e.end());
            goto_ir->genGOTO(topEnd());
            jjirnode * else_ir = ir.insertBack(e.end());

            e.enterELSE(goto_ir, else_ir);
            return true;
        }

        // loop
        bool enterLOOP(const jjtoken & t, jjsymtab & tab, jjir & ir){
            // factor, 循环因子

            // 循环，xxx，结束
            // begin, finit :   [code::assgin, 0, factor]
            // fmove        :   [code::add, factor, 1, factor]
            //                  ...
            // end, goto    :   [code::goto, fmove]
            //                  ...

            jjenvnode e;
            jjirnode * end = ir.insertBack(topEnd());

            value_t * factor = tab.newTemp();
            jjirnode * finit = ir.insertBack(end);
            finit->genUNARY(code::ASSIGN, tab.loopFactorDefault(), factor);
            finit->setToken(t);

            jjirnode * fmove = ir.insertBack(end);
            fmove->genEXPR(code::ADD, factor, tab.loopFactorForward(), factor);
            fmove->setToken(t);


            jjirnode * goto_ir = end;
            goto_ir->genGOTO(fmove);

            jjirnode * begin = finit;

            // 为了支持 循环停止 我拼了
            jjirnode * break_ir = ir.insertBack(topEnd());

            e.enterLOOP(begin, end, factor, finit, fmove, goto_ir, break_ir);
            mStack.push_back(e);

            return true;
        }

        bool enterUNTIL(const jjtoken & t, value_t * val){
            // 循环，xxx，直到xxx，结束
            // begin, finit     :   [code::assgin, 0, factor]
            // fmove            :   [code::add, factor, 1, factor]
            //                      ...
            // end, goto, cond  :   [code::IFFALSE, cond, fmove]
            jjenvnode & e = mStack.back();
            if(e.mode != jjenvnode::LOOP_MODE) return false;


            jjirnode * cond = e.node(jjenvnode::LOOP_GOTO);
            cond->genIF(code::IFFALSE, val, e.node(jjenvnode::LOOP_FMOVE));
            cond->setToken(t);
            e.enterUNTIL(cond);
            return true;
        }

        bool enterCALL(jjsymtab & tab, jjir & ir, func_t f){
            jjenvnode e;
            // 沿用上一个 jjenvnode 的 end
            jjirnode * end = topEnd();
            jjirnode * begin = ir.insertBack(end);
            value_t * result = tab.newTemp();

            begin->genARGNEW();
            e.enterCALL(begin, end, f, result);
            mStack.push_back(e);
            return true;
        }

        bool enterASSIGN(jjirnode * begin, value_t * val){
            jjenvnode e;
            // 结尾 node 继续沿用上一个 jjenvnode 的 end
            jjirnode  * end = topEnd();

            e.enterASSIGN(begin, end, val);
            mStack.push_back(e);
            return true;
        }

        bool enterSEQ(jjsymtab & tab, jjir & ir, value_t * main_val){
            jjenvnode e;
            jjirnode * begin = ir.insertBack(topEnd());
            jjirnode * end = topEnd();
            value_t * ta_val = tab.newTemp();
            begin->genUNARY(code::PUSH, main_val, ta_val);
            e.enterSEQ(begin, end, main_val, ta_val);
            mStack.push_back(e);
            return true;
        }

        bool enterPUSH(jjir & ir){
            jjenvnode & e = mStack.back();
            if(e.mode != jjenvnode::SEQ_MODE) return false;

            jjirnode * push_node = ir.insertBack(e.end());
            push_node->genUNARY(code::PUSH, e.value(jjenvnode::SEQ_MAIN), e.value(jjenvnode::SEQ_TA));
            e.enterPUSH(push_node);
            return true;
        }

        inline jjenvnode & top(){
            return mStack.back();
        }

        inline enum_t topMode(){
            return mStack.back().mode;
        }

        inline jjirnode * topBegin(){
            return mStack.back().attr[jjenvnode::BEGIN].node;
        }

        inline jjirnode * topEnd(){
            return mStack.back().attr[jjenvnode::END].node;
        }

        jjenvnode & findLOOP(){
            std::cout<<"jjenv::findLOOP mStack.size() = "<<mStack.size()<<std::endl;
            for(auto it = mStack.rbegin(); it != mStack.rend(); ++it){
                if((*it).mode == jjenvnode::LOOP_MODE){
                    return (*it);
                }
            }

            return mStack.front();
        }

        jjenvnode & findSEQ(){
            for(auto it = mStack.rbegin(); it != mStack.rend(); ++it){
                if((*it).mode == jjenvnode::SEQ_MODE)
                    return (*it);
            }

            return mStack.front();
        }

        // 退出当前环境
        void quit(){
            if(mStack.back().mode != jjenvnode::INIT_MODE){
                mStack.pop_back();
            }
        }

        // 环境清理
        void clear(){
            while(mStack.back().mode != jjenvnode::INIT_MODE)
                mStack.pop_back();
            mMainValue = nullptr;
            mLHSFlag = true;
        }
    };
}

#endif
